package com.zrkizzy.common.storage.template;

import com.zrkizzy.common.storage.dto.FileUrlDTO;
import com.zrkizzy.common.storage.exception.StorageErrorCode;
import com.zrkizzy.common.storage.strategy.FileUploadStrategy;
import com.zrkizzy.common.storage.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Objects;

/**
 * 文件上传策略模板
 *
 * @author zhangrongkang
 * @since 2023/12/13
 */
@Slf4j
@Service
public abstract class AbstractFileUploadStrategy implements FileUploadStrategy {

    /**
     * 上传文件
     *
     * @param file     文件数据
     * @param classify 文件分类
     * @return 文件路径数据传输对象
     */
    @Override
    public FileUrlDTO uploadFile(MultipartFile file, String classify) {
        String fileMd5 = null;
        try {
            // 获取文件MD5值
            fileMd5 = FileUtil.getFileMd5(file.getInputStream());
        } catch (Exception e) {
            log.error("文件上传失败: {}", e.getMessage());
            throw StorageErrorCode.FILE_UPLOAD_EXCEPTION.exception();
        }
        // 获取文件扩展名
        String fileExtName = FileUtil.getFileExtName(Objects.requireNonNull(file.getOriginalFilename()));
        // 当前文件名称
        String fileName = fileMd5 + fileExtName;
        String filePath = classify + fileName;
        if (isExist(filePath)) {
            throw StorageErrorCode.REPEAT_UPLOAD_FILE.exception();
        }
        // 上传文件
        upload(file, classify, fileName);
        // 返回文件上传数据
        return FileUrlDTO.builder().accessUrl(getFileAccessUrl(filePath)).path(getFileStoragePath(filePath)).fileName(fileName).type(fileExtName).md5(fileMd5).build();
    }

    /**
     * 获取文件路径
     *
     * @param file 文件数据
     * @param classify 文件分类
     * @return 文件路径
     */
    public String getFilePath(MultipartFile file, String classify) {
        try {
            String fileMd5 = FileUtil.getFileMd5(file.getInputStream());
            // 获取文件扩展名
            String fileExtName = FileUtil.getFileExtName(Objects.requireNonNull(file.getOriginalFilename()));
            // 获取文件路径
            return classify + fileMd5 + fileExtName;
        } catch (Exception e) {
            throw StorageErrorCode.FILE_MD5_GET_ERROR.exception();
        }
    }

    /**
     * 获取文件访问URL
     *
     * @param filePath 文件路径
     * @return 文件访问URL
     */
    public String getAccessUrl(String filePath) {
        return getFileAccessUrl(filePath);
    }

    /**
     * 判断是否存在文件
     *
     * @param filePath 文件全路径
     * @return true--存在; false--不存在
     */
    public Boolean exist(String filePath) {
        return isExist(filePath);
    }

    /**
     * 批量删除文件
     *
     * @param filePaths 文件路径集合
     * @return 是否删除成功
     */
    public Boolean deleteFile(List<String> filePaths) {
        return delete(filePaths);
    }

    /**
     * 上传文件
     *
     * @param file 文件数据
     * @param classify 文件分类
     * @param fileName 文件名称
     */
    protected abstract void upload(MultipartFile file, String classify, String fileName);

    /**
     * 获取文件访问路径
     *
     * @param filePath 文件路径
     * @return 文件访问路径
     */
    protected abstract String getFileAccessUrl(String filePath);

    /**
     * 获取文件存储路径
     *
     * @param filePath 文件路径
     * @return 文件存储路径
     */
    protected abstract String getFileStoragePath(String filePath);

    /**
     * 文件是否存在
     *
     * @param filePath 文件全路径
     * @return true--存在；false--不存在
     */
    protected abstract Boolean isExist(String filePath);

    /**
     * 批量删除文件
     *
     * @param keys 文件存储路径集合
     * @return 是否删除成功
     */
    protected abstract Boolean delete(List<String> keys);

}
